// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick.Templates as T
import Qt.labs.StyleKit

Style {

    // Define some custom delegates:

    component OverlayDelegate : StyleKitDelegate {
        // Using StyleKitDelegate as the base type is the easiest approach when creating
        // a custom delegate. A StyleKitDelegate will draw the delegate as configured by
        // the style, and give up the opportunity to place your own items on top.
        // Note that all delegates used in StyleKit, custom or not, are laid out by
        // StyleKit, so you only need to focus on the appearance.
        Rectangle {
            width: 20
            height: 15
            scale: 2.5
            radius: 255
            opacity: 0.5
            color: "transparent"
            border.width: 4
            border.color: palette.accent
        }
    }

    component UnderlayDelegate : Item {
        // If the base type is not a StyleKitDelegate, the delegate must implement two required
        // properties: 'control' and 'delegateProperties'. The former points to the Qt Quick Control
        // that uses the delegate, and the latter points to the StyleKitDelegateProperties that
        // describes how it should be styled.
        required property QtObject control
        required property StyleKitDelegateProperties delegateProperties

        width: parent.width
        height: parent.height
        implicitWidth: delegateProperties.implicitWidth
        implicitHeight: delegateProperties.implicitHeight

        Rectangle {
            id: underlay
            anchors.centerIn: parent
            width: 10 + (parent.width / 2)
            height: 10 + (parent.height / 2)
            radius: delegateProperties.radius
            scale: delegateProperties.data.underlayScale
            opacity: 0.5
            border.width: 8
            border.color: palette.accent
            Behavior on scale {
                NumberAnimation {
                    duration: 100
                }
            }
            NumberAnimation on rotation {
                loops: Animation.Infinite
                from: 0
                to: 359
                duration: 5000
            }
        }

        StyleKitDelegate {
            control: parent.control
            delegateProperties: parent.delegateProperties
        }
    }

    component SliderHandle : StyleKitDelegate {
        // You can pass your own properties from the style as well, like
        // here, where we use 'isFirst' to tell whether the delegate instance
        // represents the first or the second handle, in case of a RangeSlider.
        property bool isFirstHandle: false

        Text {
            rotation: control.vertical ? -90 : 0
            anchors.centerIn: parent
            font.pixelSize: 9
            text: {
                if (control instanceof T.RangeSlider) {
                    if (isFirstHandle)
                        return control.first.value.toFixed(0)
                    else
                        return control.second.value.toFixed(0)
                }

                return control.value.toFixed(0)
            }
        }
    }

    component NoiseDelegate : ShaderEffect {
        // Its also possible to use more advanced delegates with graphical effects.
        implicitWidth: unifiedSourceItem.implicitWidth
        implicitHeight: unifiedSourceItem.implicitHeight
        width: parent.width
        height: parent.height

        required property QtObject control
        required property StyleKitDelegateProperties delegateProperties

        // The following properties are used by the shader (noise.frag)
        property size sourceItemSize: Qt.size(unifiedSourceItem.width, unifiedSourceItem.height)
        property color borderColor: delegateProperties.border.color
        property real borderMaskEnabled: 1
        property real borderMaskThreshold: 0.001
        property real particleDensity: 0.1
        property real particleSize: 1
        property color particleColor: "black"
        property Item source: ShaderEffectSource { live: true; sourceItem: unifiedSourceItem }
        property real particleOpacity: 0.4
        property real time

        // Note: noise.frag is compiled to noise.qsb from CMakeLists.txt
        fragmentShader: "qrc:/effects/noise.qsb"

        NumberAnimation on time {
            loops: Animation.Infinite
            from: 0
            to: Math.PI * 2
            duration: 1000
        }

        StyleKitDelegate {
            id: unifiedSourceItem
            control: parent.control
            delegateProperties: parent.delegateProperties
            visible: false
        }
    }

    component WavingQt : ShaderEffect {
        implicitWidth: delegateProperties.implicitWidth
        implicitHeight: delegateProperties.implicitHeight

        required property QtObject control
        required property StyleKitDelegateProperties delegateProperties

        // The following properties are used by the shader (wave.frag)
        property real amplitude: 0.04 * 0.5
        property real frequency: 20
        property real time

        NumberAnimation on time {
            loops: Animation.Infinite
            from: 0
            to: Math.PI * 2
            duration: 600
        }

        // Note: wave.frag is compiled to wave.qsb from CMakeLists.txt
        fragmentShader: "qrc:/effects/wave.qsb"

        property Item sourceItem: ShaderEffectSource {
            sourceItem: Image {
                width: 40
                height: 40
                source: "qrc:/images/qt.png"
                visible: false
            }
        }
    }

    component CustomShadowDelegate : Item {
        required property QtObject control
        required property StyleKitDelegateProperties delegateProperties

        x: delegateProperties.shadow.verticalOffset
        y: delegateProperties.shadow.horizontalOffset
        width: parent.width
        height: parent.height

        Rectangle {
            width: parent.width
            height: parent.height
            radius: parent.delegateProperties.radius
            color: parent.delegateProperties.shadow.color
            opacity: parent.delegateProperties.shadow.opacity
        }

        Text {
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            anchors.rightMargin: 10
            color: "white"
            text: "Custom shadow"
        }
    }

    // Define the style itself, and tell it to use the custom delegates to render
    // the controls (instead of the otherwise default StyleKitDelegate):

    control {
        background.radius: 10
        background.color: "lightgray"
        hovered.background.color: "gray"
        background.shadow.color: "gray"
        background.shadow.verticalOffset: 4
        background.shadow.horizontalOffset: 4
        pressed.background.scale: 0.95
    }

    checkBox.checked.indicator.delegate: OverlayDelegate {}
    radioButton.checked.indicator.foreground.delegate: OverlayDelegate {}
    switchControl.handle.delegate: WavingQt {}

    abstractButton {
        background {
            delegate: UnderlayDelegate {}
            shadow.opacity: 0
            data: QtObject {
                // When using custom delegates, you might need pass properties to it that
                // should change per state. The 'data' property can be used for this purpose.
                property real underlayScale: 1.1
            }
        }
        hovered.background.data: QtObject {
            property real underlayScale: 1.4
        }
    }

    slider {
        background.visible: true
        background.delegate: NoiseDelegate {}
        indicator.delegate: NoiseDelegate {}
        indicator.foreground.delegate: NoiseDelegate {}
        handle.delegate: SliderHandle { isFirstHandle: true }
        handle.second.delegate: SliderHandle { isFirstHandle: false }
    }

    textField {
        background.shadow.verticalOffset: 14
        background.shadow.horizontalOffset: 14
        background.shadow.delegate: CustomShadowDelegate {}
        // verify that the delegate is allowed to change per state
        pressed.background.shadow.delegate: CustomShadowDelegate {}
        variations: Variation {
            button.background {
                delegate: null
                implicitWidth: 30
                implicitHeight: 20
                margins: 10
                shadow.color: "transparent"
            }
        }
    }
}
